import 'package:camera/camera.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:platform_service/src/scanner/qr_code_dart_scan/lib/src/util/extensions.dart';

import '../../../scanner.dart';
import '../qr_code_dart_scan.dart';

///
/// Created by
///
/// ─▄▀─▄▀
/// ──▀──▀
/// █▀▀▀▀▀█▄
/// █░░░░░█─█
/// ▀▄▄▄▄▄▀▀
///
/// Rafaelbarbosatec
/// on 12/08/21

enum TypeCamera { back, front }

enum TypeScan { live, takePicture }

typedef TakePictureButtonBuilder = Widget Function(
  BuildContext context,
  QRCodeDartScanController controller,
  bool loading,
);

class QRCodeDartScanView extends StatefulWidget {
  final TypeCamera typeCamera;
  final TypeScan typeScan;
  final ValueChanged<Result>? onCapture;
  final bool scanInvertedQRCode;

  /// Use to limit a specific format
  /// If null use all accepted formats
  final List<BarcodeFormat> formats;
  final QRCodeDartScanController? controller;
  final QRCodeDartScanResolutionPreset resolutionPreset;
  final Widget? child;
  final double? widthPreview;
  final double? heightPreview;
  final TakePictureButtonBuilder? takePictureButtonBuilder;
  final NDPlatformCallBackHandler platformCallBackHandler;

  const QRCodeDartScanView({
    Key? key,
    this.typeCamera = TypeCamera.back,
    this.typeScan = TypeScan.live,
    this.onCapture,
    this.scanInvertedQRCode = false,
    this.resolutionPreset = QRCodeDartScanResolutionPreset.medium,
    this.controller,
    this.formats = QRCodeDartScanDecoder.acceptedFormats,
    this.child,
    this.takePictureButtonBuilder,
    required this.platformCallBackHandler,
    this.widthPreview = double.maxFinite,
    this.heightPreview = double.maxFinite,
  }) : super(key: key);

  @override
  QRCodeDartScanViewState createState() => QRCodeDartScanViewState();
}

class QRCodeDartScanViewState extends State<QRCodeDartScanView>
    implements DartScanInterface {
  CameraController? controller;
  late QRCodeDartScanController qrCodeDartScanController;
  late QRCodeDartScanDecoder dartScanDecoder;
  bool initialized = false;
  bool processingImg = false;

  @override
  TypeScan typeScan = TypeScan.live;

  @override
  void initState() {
    typeScan = widget.typeScan;
    dartScanDecoder = QRCodeDartScanDecoder(formats: widget.formats);
    _initController();
    _initPlatformCallBackHandler();
    super.initState();
  }

  /// 新增控制方法
  void _initPlatformCallBackHandler() {
    var _platformCallBackHandler = widget.platformCallBackHandler;
    _platformCallBackHandler.controllerDispose = () {
      controller?.dispose();
      return Future.value();
    };
    _platformCallBackHandler.start = () {
      _startImageStream();
      return Future.value();
    };
    _platformCallBackHandler.stop = () {
      _stopImageStream();
      return Future.value();
    };
    _platformCallBackHandler.pause = () {
      controller?.pausePreview();
      controller?.pauseVideoRecording();
      return Future.value();
    };
    _platformCallBackHandler.resume = () {
      controller?.resumePreview();
      controller?.resumeVideoRecording();
      return Future.value();
    };
  }

  @override
  void didUpdateWidget(covariant QRCodeDartScanView oldWidget) {
    _initPlatformCallBackHandler();
    super.didUpdateWidget(oldWidget);
  }

  @override
  void dispose() {
    controller?.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return AnimatedSwitcher(
      duration: const Duration(milliseconds: 300),
      child: initialized ? _getCameraWidget(context) : loadingWidget(),
    );
  }

  int initRetryCount = 0;

  void _initController() async {
    try {
      final cameras = await availableCameras();
      var camera = cameras.first;
      if (widget.typeCamera == TypeCamera.front && cameras.length > 1) {
        camera = cameras[1];
      }
      controller = CameraController(
        camera,
        widget.resolutionPreset.toResolutionPreset(),
        enableAudio: false,
        imageFormatGroup: ImageFormatGroup.yuv420,
      );
      qrCodeDartScanController =
          widget.controller ?? QRCodeDartScanController();
      await controller!.initialize();
      qrCodeDartScanController.configure(controller!, this);
      // 有bug 暂时不支持闪光灯设置
      // try {
      //   controller?.setFlashMode(FlashMode.auto);
      // } catch (err) {
      //   print('init setFlashMode auto:$err');
      // }
      if (typeScan == TypeScan.live) {
        _startImageStream();
      }
      postFrame(() {
        setState(() {
          initialized = true;
        });
      });
    } catch (err) {
      await controller?.dispose();
      initRetryCount++;
      if (initRetryCount < 4) {
        _initController();
      }
      print('QRCodeDartScanView _initController err:$err');
      return Future.error(err.toString());
    }
  }

  /// 是否自动拍照解析
  bool autoTakeImageDecode = false;

  Future _startH5AutoTakePictureDecode() async {
    if (!mounted) return Future.value();
    if (autoTakeImageDecode) {
      if (initialized) {
        try {
          print('ncScanner QRCodeDartScanView 开始自动拍照解析');
          await takePictureAndDecode();
          await Future.delayed(const Duration(milliseconds: 500), () {});
        } catch (err) {
          setState(() {
            initialized = false;
          });
          await controller?.dispose();
          print(
              'ncScanner QRCodeDartScanView _startH5AutoTakePictureDecode 异常:$err');
          initRetryCount++;
          if (initRetryCount < 4) {
            _initController();
          }
          return Future.value();
        }
      } else {
        print('ncScanner QRCodeDartScanView 自动拍照解析 等待initialized：$initialized');
        await Future.delayed(const Duration(milliseconds: 1000), () {});
      }
      _startH5AutoTakePictureDecode();
    } else {
      print('ncScanner QRCodeDartScanView 已停止自动拍照解析');
    }
  }

  void _startImageStream() {
    if (kIsWeb) {
      autoTakeImageDecode = true;
      _startH5AutoTakePictureDecode();
    } else {
      /// 自动获取图片识别 只支持 Android端 和 IOS端， H5端需要自己
      controller?.startImageStream(_imageStream);
    }
  }

  void _stopImageStream() {
    if (kIsWeb) {
      autoTakeImageDecode = false;
    } else {
      /// 自动获取图片识别 只支持 Android端 和 IOS端， H5端需要自己
      controller?.stopImageStream();
    }
  }

  void _imageStream(CameraImage image) async {
    if (!qrCodeDartScanController.scanEnabled) return;
    if (processingImg) return;
    processingImg = true;
    _processImage(image);
  }

  void _processImage(CameraImage image) async {
    final decoded = await dartScanDecoder.decodeCameraImage(
      image,
      scanInverted: widget.scanInvertedQRCode,
    );

    if (decoded != null && mounted) {
      widget.onCapture?.call(decoded);
    }

    processingImg = false;
  }

  @override
  Future<void> takePictureAndDecode() async {
    if (typeScan == TypeScan.takePicture) {
      if (processingImg) return;
      setState(() {
        processingImg = true;
      });
    }

    final xFile = await controller?.takePicture();

    if (xFile != null) {
      final decoded = await dartScanDecoder.decodeFile(
        xFile,
        scanInverted: widget.scanInvertedQRCode,
      );

      if (mounted) {
        if (decoded != null) {
          widget.onCapture?.call(decoded);
        } else if (typeScan == TypeScan.takePicture) {
          widget.onCapture?.call(Result.full('', [], 0, null,
              BarcodeFormat.qrCode, DateTime.now().millisecondsSinceEpoch));
        }
      }
    }
    if (typeScan == TypeScan.takePicture) {
      setState(() {
        processingImg = false;
      });
    }
    return Future.value();
  }

  Widget _buildButton() {
    return widget.takePictureButtonBuilder?.call(
          context,
          qrCodeDartScanController,
          processingImg,
        ) ??
        _ButtonTakePicture(
          onTakePicture: takePictureAndDecode,
          isLoading: processingImg,
        );
  }

  @override
  Future<void> changeTypeScan(TypeScan type) async {
    if (typeScan == type) {
      return;
    }
    if (typeScan == TypeScan.takePicture) {
      _startImageStream();
    } else {
      await controller?.stopImageStream();
      processingImg = false;
    }
    setState(() {
      typeScan = type;
    });
  }

  Widget _getCameraWidget(BuildContext context) {
    return SizedBox(
      width: widget.widthPreview,
      height: widget.heightPreview,
      child: CameraPreview(
        controller!,
        child: Stack(
          children: [
            if (typeScan == TypeScan.takePicture) _buildButton(),
            widget.child ?? const SizedBox.shrink(),
            _scannerWidget()
          ],
        ),
      ),
    );
  }

  Widget loadingWidget() {
    return Container(
      height: widget.heightPreview ?? double.maxFinite,
      width: widget.widthPreview ?? double.maxFinite,
      child: Center(
        child: Container(
          height: 48,
          width: 48,
          padding: const EdgeInsets.all(3),
          child: const CircularProgressIndicator(
            valueColor: AlwaysStoppedAnimation(Color(0xff0006ff)),
            strokeWidth: 1.2,
          ),
        ),
      ),
    );
  }

  bool flashOpen = false;

  Widget _scannerWidget() {
    return Align(
      alignment: Alignment.center,
      child: SizedBox(
        height: 196,
        child: Column(
          children: [
            const Spacer(),
            SizedBox(
              width: 152,
              height: 152,
              child: Stack(
                children: [
                  Positioned(
                    left: 1,
                    right: 1,
                    top: 1,
                    bottom: 1,
                    child: Container(
                      decoration: BoxDecoration(
                        color: Colors.transparent,
                        borderRadius: BorderRadius.circular(2),
                        border: Border.all(
                            color: Colors.indigoAccent,
                            strokeAlign: BorderSide.strokeAlignCenter,
                            width: 0.5),
                      ),
                      child: const SizedBox(),
                    ),
                  ),
                  Positioned(
                    left: 0,
                    top: 0,
                    child: Container(
                      height: 2,
                      width: 12,
                      color: Colors.indigoAccent,
                    ),
                  ),
                  Positioned(
                    left: 0,
                    top: 0,
                    child: Container(
                      height: 12,
                      width: 2,
                      color: Colors.indigoAccent,
                    ),
                  ),
                  Positioned(
                    right: 0,
                    top: 0,
                    child: Container(
                        height: 2, width: 12, color: Colors.indigoAccent),
                  ),
                  Positioned(
                    right: 0,
                    top: 0,
                    child: Container(
                      height: 12,
                      width: 2,
                      color: Colors.indigoAccent,
                    ),
                  ),
                  Positioned(
                    left: 0,
                    bottom: 0,
                    child: Container(
                      height: 2,
                      width: 12,
                      color: Colors.indigoAccent,
                    ),
                  ),
                  Positioned(
                    left: 0,
                    bottom: 0,
                    child: Container(
                      height: 12,
                      width: 2,
                      color: Colors.indigoAccent,
                    ),
                  ),
                  Positioned(
                    right: 0,
                    bottom: 0,
                    child: Container(
                      height: 2,
                      width: 12,
                      color: Colors.indigoAccent,
                    ),
                  ),
                  Positioned(
                    right: 0,
                    bottom: 0,
                    child: Container(
                      height: 12,
                      width: 2,
                      color: Colors.indigoAccent,
                    ),
                  ),
                ],
              ),
            ),
            const Spacer(),
            // 有bug 暂时不支持闪光灯设置
            // const SizedBox(height: 12),
            // StatefulBuilder(builder: (context, state) {
            //   return InkWell(
            //     onTap: () {
            //       try {
            //         flashOpen = !flashOpen;
            //         controller?.setFlashMode(
            //             flashOpen ? FlashMode.always : FlashMode.off);
            //       } catch (err) {
            //         print('toggle setFlashMode:$err');
            //       }
            //       state(() {});
            //     },
            //     child: Icon(
            //       flashOpen ? Icons.flashlight_on : Icons.flashlight_off,
            //       size: 32,
            //       color: Colors.white,
            //     ),
            //   );
            // }),
          ],
        ),
      ),
    );
  }
}

class _ButtonTakePicture extends StatelessWidget {
  final VoidCallback onTakePicture;
  final bool isLoading;

  const _ButtonTakePicture(
      {Key? key, required this.onTakePicture, this.isLoading = false})
      : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Align(
      alignment: Alignment.bottomCenter,
      child: Container(
        height: 150,
        color: Colors.transparent,
        child: Center(
          child: InkWell(
            onTap: onTakePicture,
            child: Container(
              width: 56,
              height: 56,
              decoration: BoxDecoration(
                color: Colors.white,
                borderRadius: BorderRadius.circular(28),
              ),
              child: Container(
                margin: const EdgeInsets.all(4),
                decoration: BoxDecoration(
                  color: Colors.red,
                  borderRadius: BorderRadius.circular(28),
                ),
                child: isLoading
                    ? const Center(
                        child: SizedBox(
                          width: 40,
                          height: 40,
                          child: CircularProgressIndicator(
                            valueColor:
                                AlwaysStoppedAnimation<Color>(Colors.white),
                          ),
                        ),
                      )
                    : const SizedBox.shrink(),
              ),
            ),
          ),
        ),
      ),
    );
  }
}
